package com.xgq.drink.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;

@Slf4j
@Component
public class JwtTokenUtil {
    @Value("${security.jwt.secret}")
    private String secret;

    @Value("${security.jwt.expiration}")
    private long expiration;

    @Autowired
    private RedisUtil redisUtil;

    public String generateToken(Long userId) {
        Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("Asia/Shanghai"));
        Date issuedAt = calendar.getTime();
        calendar.add(Calendar.MILLISECOND, (int) expiration); // expiration 单位为毫秒
        Date expirationDate = calendar.getTime();
        Algorithm algorithm = Algorithm.HMAC256(secret);
        log.info("为用户ID {} 生成Token，过期时间: {}", userId, expirationDate);
        return JWT.create()
                .withSubject(userId.toString())
                .withIssuedAt(issuedAt)
                .withExpiresAt(expirationDate)
                .sign(algorithm);
    }
    public String generateStoreToken(String userId, Long storeId) {
        Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("Asia/Shanghai"));
        Date issuedAt = calendar.getTime();
        calendar.add(Calendar.MILLISECOND, (int) expiration);
        Date expirationDate = calendar.getTime();

        Algorithm algorithm = Algorithm.HMAC256(secret);
        log.info("生成店铺Token - 用户ID: {} 店铺ID: {} 过期时间: {}", userId, storeId, expirationDate);

        return JWT.create()
                .withSubject(userId.toString())
                .withClaim("storeId", storeId)  // 新增店铺ID声明
                .withIssuedAt(issuedAt)
                .withExpiresAt(expirationDate)
                .sign(algorithm);
    }
    // 新增店铺ID解析方法
    public Long getStoreIdFromToken(String token) {
        String bearerPrefix = "Bearer ";
        token = token.substring(bearerPrefix.length());
        DecodedJWT jwt = JWT.decode(token);
        return jwt.getClaim("storeId").asLong();
    }
    public Long getStoreIdFromToken2(String token) {
        DecodedJWT jwt = JWT.decode(token);
        return jwt.getClaim("storeId").asLong();
    }
    public String getUserIdFromToken(String token) {
        log.debug("从Token中获取用户ID, token: {}", token);
        if (token == null || token.isEmpty()) {
            log.warn("Token为空，无法获取用户ID");
            return null;
        }
        try {
            // 去掉 Bearer 前缀
            String bearerPrefix = "Bearer ";
            if (token.startsWith(bearerPrefix)) {
                log.debug("Token包含Bearer前缀，将去除前缀");
                token = token.substring(bearerPrefix.length());
            }

            DecodedJWT decodedJWT = JWT.decode(token);
            String userId = decodedJWT.getSubject();
            log.debug("成功从Token中获取用户ID: {}", userId);
            return userId;
        } catch (JWTDecodeException e) {
            log.error("解码JWT Token时出错: {}", e.getMessage(), e);
            return null;
        }
    }
    
    public Long getUserIdFromRequest(HttpServletRequest request){
        String token = request.getHeader("Authorization");
        log.debug("从请求中获取用户ID, Authorization头: {}", token);
        if (token == null || token.isEmpty()) {
            log.warn("请求中未找到Authorization头");
            return null;
        }
        try {
            String bearerPrefix = "Bearer ";
            if (token.startsWith(bearerPrefix)) {
                log.debug("Token包含Bearer前缀，将去除前缀");
                token = token.substring(bearerPrefix.length());
            }
            DecodedJWT decodedJWT = JWT.decode(token);
            String userId = decodedJWT.getSubject();
            log.debug("成功从请求中获取用户ID: {}", userId);
            return Long.valueOf(userId);
        } catch (JWTDecodeException e) {
            log.error("从请求中解码JWT Token时出错: {}", e.getMessage(), e);
            return null;
        }
    }

    public boolean validateToken(String token, String username) {
        log.debug("验证Token, token: {}, username: {}", token, username);
        if (token == null || token.isEmpty() || username == null || username.isEmpty()) {
            log.warn("Token或username为空，无法验证");
            return false;
        }
        try {
            if (redisUtil.isTokenBlacklisted(token)) {
                log.warn("Token在黑名单中，拒绝访问");
                return false;
            }

            Algorithm algorithm = Algorithm.HMAC256(secret);
            JWTVerifier verifier = JWT.require(algorithm).withSubject(username).build();
            DecodedJWT decodedJWT = verifier.verify(token);

            // 检查是否过期
            boolean isExpired = decodedJWT.getExpiresAt().before(new Date());
            if (isExpired) {
                log.warn("Token已过期");
            } else {
                log.debug("Token验证成功");
            }
            return !isExpired;
        } catch (Exception e) {
            log.error("Token验证异常: {}", e.getMessage(), e);
            return false;
        }
    }
    
    public long getExpirationFromToken(String token) {
        log.debug("从Token中获取过期时间, token: {}", token);
        try {
            // 解析 Token
            DecodedJWT decodedJWT = JWT.decode(token);
            Date expirationDate = decodedJWT.getExpiresAt();

            // 格式化输出时间（显示时区）
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
            sdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai")); // 修正时区为上海
            log.debug("Token过期时间（北京时间）: {}", sdf.format(expirationDate));

            // 计算剩余时间
            long currentTime = System.currentTimeMillis();
            long expirationTime = expirationDate.getTime();
            long remaining = expirationTime - currentTime;

            // 添加详细日志
            log.debug("当前系统时间（毫秒）: {}", currentTime);
            log.debug("Token过期时间（毫秒）: {}", expirationTime);
            log.debug("剩余时间（毫秒）: {}", remaining);

            // 处理负数情况
            if (remaining < 0) {
                log.warn("Token已过期");
                return -1; // 返回 -1 表示 Token 已过期
            }

            return remaining;
        } catch (JWTDecodeException e) {
            log.error("解析Token失败: {}", e.getMessage(), e);
            return -1; // 返回 -1 表示解析失败
        }
    }
}